import { AnyObject } from 'antd/es/_util/type';
import { ConfigProvider, Flex, Form, Table, TableProps } from 'antd';
import { EmptyData, SearchForm, SearchProps, ThemeMode } from '@ycx/ui';
import { keepPreviousData, QueryKey, useQuery } from '@tanstack/react-query';
import {
  ForwardedRef,
  forwardRef,
  ReactNode,
  useEffect,
  useImperativeHandle,
  useMemo,
  useState,
} from 'react';
import { Page } from '#/api.ts';
import { useEvent } from 'react-use';
import { debounce } from 'lodash-es';
import { createStyles } from 'antd-style';
import { useTheme } from '@/store/settingsStore.ts';
import { useCatch } from '@/hooks';

export type ITableProps<Entity, ApiParams> = {
  api: {
    fn: (params: ApiParams & Page) => Promise<{ data: Entity[]; total: number }>;
    /*查询键，请确保唯一性，建议为 bizName-action 例如 user-query*/
    key: QueryKey;
  };
  // fields?: (Required<SearchProps<ApiParams>>['fields'][number] & { roleList?: RoleType[] })[];
  fields?: SearchProps<ApiParams>['fields'];
  extra?: ReactNode;
} & TableProps<Entity>;

export type ITableRef = {
  refetch: () => void;
};

const ITable = forwardRef(
  <Entity extends AnyObject, ApiParams extends AnyObject>(
    { api, fields = [], columns, extra, ...rest }: ITableProps<Entity, ApiParams>,
    ref: ForwardedRef<ITableRef>,
  ) => {
    const catchFn = useCatch();
    const theme = useTheme();
    const [apiParams, setApiParams] = useState<ApiParams>(() => {
      return Object.fromEntries(
        fields
          .filter((field) => field.initialValue)
          .map((field) => [field.name, field.initialValue]),
      ) as ApiParams;
    });

    const [page, setPage] = useState<Page>({ page: 1, limit: 10, order: 'id DESC' });

    const { data, refetch, isFetching } = useQuery({
      placeholderData: keepPreviousData,
      queryKey: [...api.key, apiParams, page],
      queryFn: () => catchFn(() => api.fn({ ...apiParams, ...page })),
    });

    const pagination = useMemo<TableProps['pagination']>(() => {
      return {
        current: page.page,
        pageSize: page.limit,
        total: data?.total ?? 0,
        showSizeChanger: true,
        showTotal: (total) => `共 ${total} 条数据`,
        showQuickJumper: true,
        //TODO: order没写完，目前是硬编码
        onChange: (page, pageSize) => setPage({ page, limit: pageSize, order: 'id DESC' }),
      };
    }, [data?.total, page.limit, page.page]);

    const [scrollY, setScrollY] = useState(550);

    const { styles } = createStyles(({ css }) => {
      return {
        table: css`
          & .ant-table-cell {
            border-color: ${!data || data?.data.length === 0
              ? 'transparent'
              : 'var(--ycx-divider-color)'} !important;
          }
        `,
        empty: css`
          &.ant-empty .ant-empty-image {
            height: auto !important;
          }
        `,
      };
    })();

    const tableProps = useMemo<TableProps>(
      () => ({
        columns,
        dataSource: data?.data,
        loading: isFetching,
        pagination,
        scroll: {
          x: rest.scroll?.x ?? '100%', //不推荐设置 scroll.x 会导致column的width和ellipsis失效
          y: rest.scroll?.y ?? scrollY ?? 500,
        },
        locale: {
          emptyText: (
            <EmptyData
              imageStyle={{
                width: '100%',
                height: `${scrollY > 390 ? '100%' : scrollY - 60 + 'px'}`,
                minHeight: '150px',
              }}
              theme={theme}
            />
          ),
        },
      }),
      [columns, data?.data, isFetching, pagination, rest.scroll?.x, rest.scroll?.y, scrollY, theme],
    );

    const [form] = Form.useForm<ApiParams>();

    const searchProps: SearchProps<ApiParams> = {
      wrapperClassName: 'search-wrapper',
      form,
      fields,
      onSearch: async (formValues, isReset) => {
        if (JSON.stringify(formValues) === JSON.stringify(apiParams)) {
          await refetch();
        } else {
          setApiParams(formValues);
          setPage({ ...page, page: 1 });
        }
        if (isReset) setPage({ ...page, page: 1 });
      },
      onExpand: () => {
        Promise.resolve().then(setTableHeight);
      },
    };

    useImperativeHandle(ref, () => ({
      refetch,
    }));

    const setTableHeight = () => {
      const baseHeight = document.querySelector('.main-content')?.clientHeight ?? 850;
      const searchHeight = document.querySelector('.search-wrapper')?.clientHeight ?? 0;
      const extraHeight = document.querySelector('.extra-wrapper')?.clientHeight ?? 0;

      setScrollY(baseHeight - 48 - searchHeight - extraHeight - 80 - 54.5);
    };

    useEffect(() => {
      setTableHeight();
    }, []);

    useEvent('resize', debounce(setTableHeight, 100));

    return (
      <>
        <SearchForm<ApiParams> {...searchProps} />

        {extra ? (
          <Flex className="extra-wrapper pb-6" justify="end">
            {extra}
          </Flex>
        ) : null}

        <ConfigProvider
          theme={{
            components: {
              Table: {
                colorBgContainer:
                  !data || data?.data.length === 0
                    ? 'transparent'
                    : theme === ThemeMode.Light
                      ? '#F3F7FF'
                      : '#212535',
              },
            },
          }}
        >
          <Table<Entity> {...rest} {...tableProps} className={styles.table} />
        </ConfigProvider>
      </>
    );
  },
);

export default ITable;
